package cn.flying.cloud.base.common.utils.json;

import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

import cn.flying.cloud.base.common.enums.RtCodeEnum;
import cn.flying.cloud.base.common.exception.CommonException;

/**
 * Jackson 操作工具类
 *
 * @author: admin
 * @date: 2022年04月02日 22:30
 * @version: 1.0
 */
public class JacksonUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);

        //序列化BigDecimal时之间输出原始数字还是科学计数, 默认false, 即是否以toPlainString()科学计数方式来输出
        objectMapper.disable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
        //允许将JSON空字符串强制转换为null对象值
        objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        //允许单个数值当做数组处理
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

        //禁止重复键, 抛出异常
        objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
        //禁止使用int代表Enum的order()來反序列化Enum, 抛出异常
        objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
        //有属性不能映射的时候不报错
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        //使用null表示集合类型字段是时不抛异常
        objectMapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
        //对象为空时不抛异常
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        //允许在JSON中使用c/c++风格注释
        objectMapper.enable(JsonParser.Feature.ALLOW_COMMENTS);
        //允许未知字段
        objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN);
        //在JSON中允许未引用的字段名
        objectMapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
        //时间格式
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //识别单引号
        objectMapper.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
        //识别Java8时间
        objectMapper.registerModule(new ParameterNamesModule());
        objectMapper.registerModule(new Jdk8Module());
        objectMapper.registerModule(new JavaTimeModule());
    }

    public JacksonUtil() {
    }

    /**
     * JSON 序列化
     *
     * @param obj
     * @return
     */
    public static String serializer(Object obj) {
        try {
            if (obj == null) {
                return null;
            } else if (obj instanceof String) {
                return (String) obj;
            } else {
                return objectMapper.writeValueAsString(obj);
            }
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "序列化失败", e);
        }
    }

    /**
     * JSON 序列化  有顺序
     *
     * @param obj
     * @return
     */
    public static String serializer(Object obj, boolean sort) {
        try {
            if (obj == null) {
                return null;
            } else if (obj instanceof String) {
                return (String) obj;
            } else {
                if (sort) {
                    objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
                }
                String json = objectMapper.writeValueAsString(obj);
                if (sort) {
                    objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, false);
                }
                return json;
            }
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "序列化失败", e);
        }
    }

    /**
     * JSON 序列化，忽略null字段
     *
     * @param obj
     * @return
     */
    public static String serialIgnoreNull(Object obj) {
        try {
            if (obj == null) {
                return null;
            } else if (obj instanceof String) {
                return (String) obj;
            } else {
                objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
                return objectMapper.writeValueAsString(obj);
            }
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "序列化失败", e);
        }
    }

    /**
     * JSON 反序列化
     *
     * @param jsonString
     * @param clazz
     * @return
     */
    public static <T> T deserialize(String jsonString, Class<T> clazz) {
        if (jsonString == null || "".equals(jsonString)) {
            return null;
        }
        try {
            objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return objectMapper.readValue(jsonString, clazz);
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "反序列化失败", e);
        }
    }

    /**
     * JSON 反序列化
     *
     * @param jsonString
     * @param type
     * @return
     */
    public static Object deserialize(String jsonString, TypeReference<?> type) {
        if (jsonString == null || "".equals(jsonString)) {
            return null;
        }
        try {
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return objectMapper.readValue(jsonString, type);
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "反序列化失败", e);
        }
    }

    /**
     * 字符串转换为 Map<String, Object>
     *
     * @param jsonString
     * @return
     */
    public static Map<String, Object> parseToMap(String jsonString) {
        if (jsonString == null || "".equals(jsonString)) {
            return null;
        }
        try {
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            return objectMapper.readValue(jsonString, Map.class);
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "反序列化失败", e);
        }
    }

    /**
     * 字符串转换为 Map<String, T>
     *
     * @param jsonString
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Map<String, T> parseToMap(String jsonString, Class<T> clazz) {
        if (jsonString == null || jsonString == "") {
            return null;
        }
        try {
            Map<String, Map<String, Object>> map = (Map<String, Map<String, Object>>) objectMapper.readValue(jsonString, new TypeReference<Map<String, T>>() {
            });
            Map<String, T> result = new HashMap<>();
            for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
                result.put(entry.getKey(), mapToBean(entry.getValue(), clazz));
            }
            return result;
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "反序列化失败", e);
        }

    }

    /**
     * 将 Map 转换为 JavaBean
     *
     * @param map
     * @param clazz
     * @return
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
        return objectMapper.convertValue(map, clazz);
    }

    /**
     * 将 Map 转换为 JSON
     *
     * @param map
     * @return
     */
    public static String mapToJson(Map<String, Object> map) {
        try {
            return objectMapper.writeValueAsString(map);
        } catch (Exception e) {
            throw new CommonException(RtCodeEnum.R90000.getCode(), "序列化失败", e);
        }
    }

    /**
     * 将 JSON 对象转换为 JavaBean
     *
     * @param obj
     * @param clazz
     * @return
     */
    public static <T> T objToBean(Object obj, Class<T> clazz) {
        return objectMapper.convertValue(obj, clazz);
    }


}
